#include "my_log.hpp"
#include "block_queue.hpp"
#include "thread_pool.hpp"
#include "basic_task.hpp"
#include "remote_contral.hpp"
#include <string>
#include <iostream>
#include <sys/types.h>          
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define MAX_THREAD_NUM 20
#define MAX_COMMAND_LEN 100

class udp_server
{
public:
    udp_server(const short& port)
        : udp_fd(0)
    {
        udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (udp_fd == -1)
        {
            lg.basic_print(level::FATAL, std::make_tuple("connot create socket fd "), true, true);
        }
        struct sockaddr_in _server_info;
        memset(&_server_info, 0, sizeof(struct sockaddr_in));
        _server_info.sin_family = AF_INET;
        _server_info.sin_addr.s_addr = INADDR_ANY;
        _server_info.sin_port = htons(port);
        bind(udp_fd, static_cast<sockaddr*>(static_cast<void*>(&_server_info)), static_cast<socklen_t>(sizeof(_server_info)));
        if (udp_fd == -1)
        {
            lg.basic_print(level::FATAL, std::make_tuple("connot bind socket fd "), true, true);
        }
    }

    void start()
    {
        char command[MAX_COMMAND_LEN] = {};
        workers<MAX_THREAD_NUM> ws;
        struct sockaddr_in client_info;
        socklen_t client_len = sizeof(client_info);
        memset(&client_info, 0, sizeof(struct sockaddr_in));
        remote_contral task;
        while (1)
        {
            ssize_t n = recvfrom(udp_fd, command, MAX_COMMAND_LEN, 0, static_cast<struct sockaddr*>(static_cast<void*>(&client_info)), &client_len);
            if (n > 0)
            {
                command[n] = '\0';
                task = command;
                ws.add_task(&task);
                lg.basic_print(level::DEBUG, std::make_tuple("ip received, %s ", inet_ntoa(client_info.sin_addr)), false);
                lg.basic_print(level::DEBUG, std::make_tuple("port received, %lu ", ntohs(client_info.sin_port)), true);
                sendto(udp_fd, "task completed", 15, 0, static_cast<struct sockaddr*>(static_cast<void*>(&client_info)), client_len);
            }
        }
    }
private:
    int udp_fd;
};

int main(int argc, const char** argv)
{
    if (argc != 2)
    {
        std::cout << "Format mismatched, start failed." << std::endl;
        std::cout << "example input: program_name port" << std::endl;
        lg.basic_print(level::FATAL, std::make_tuple("input format err"), true);
        std::terminate();
    }
    udp_server u(atoi(argv[1]));
    u.start();
    return 0;
}